<template>
  <div :id="pageId" class="graph-container" ref="container"></div>
</template>

<script>
// import G6 from '@antv/g6'
import G6 from '../../../../../../public/g6/index'
import { initBehavors } from '../../behavior'
import Grid from '@antv/g6/build/grid'
import { getRandomPosition } from '@/views/components/zstp/utils/index'

export default {
  data() {
    return {
      pageId: 'graph-container',
      graph: null,
      pageHeight: 0,
      pageWidth: 0,
      grid: null,
      shakingNodes: new Set(),
      animationFrameId: null,
      draggingNodeId: null
    }
  },
  props: {
    height: {
      type: Number,
      default: 0
    },
    width: {
      type: Number,
      default: 0
    },
    data: {
      type: Object,
      default: () => {}
    },
    uploadJsonData: {
      type: Object,
      default: () => {}
    }
  },
  watch: {
    uploadJsonData: {
      handler(val) {
        if (Object.keys(val).length > 0) {
          // this.graph.changeData(this.data)
          if (this.graph) {
            this.graph.destroy()
          }
          this.init()
          // this.graph.clear()
          // this.graph.read(val)
        }
      }
    }
  },
  created() {
    initBehavors()
    // 监听保存导入信息
    // this.$bus.$on('updateJsonData', data => {
    //   this.updateJsonData(data)
    // })
  },
  mounted() {
    this.$nextTick(() => {
      this.init()
    })
    this.$bus.$on('offEvent', () => {
      if (this.graph) {
        this.graph.off('mouseup')
      }
    })
  },
  methods: {
    // 更新读取上传文件的内容（已废弃）
    updateJsonData(val) {
      let result = getRandomPosition(this, val, 1000, 600)
      let allData = {
        nodes: result.nodes.map(item => {
          return {
            ...item,
            label: item.name,
            size: ['80'],
            x: Number(item.x),
            y: Number(item.y)
          }
        }),
        edges: result.edges.map(item => {
          return {
            id: item.id,
            source: item.sourceId,
            sourceId: item.sourceId,
            target: item.targetId,
            targetId: item.targetId,
            shape: 'customEdge',
            type: 'edge',
            name: item.name ? item.name : '',
            labelCfg: {
              autoRotate: true,
              style: {
                fill: 'red',
                stroke: 'white',
                lineWidth: 5
              }
            },
            // 线的颜色
            style: {
              fill: 'l(0) 0:#ffffff 0.5:#7ec2f3 1:#1890ff',
              stroke: '#5B8FF9',
              lineWidth: 1
            }
          }
        })
      }

      this.graph.clear()
      this.graph.data(allData)
      this.graph.render()
    },
    init() {
      const _that = this
      _that.pageHeight = _that.height // 控制画布高度,G6不支持百分比，需要具体的像素来布局
      _that.pageWidth = _that.width // 控制画布宽度
      _that.graph = new G6.Graph({
        container: _that.$refs.container,
        height: _that.$refs.container.scrollHeight, // 不用组件传过来的宽高，根据容器的宽高来布局
        width: _that.$refs.container.scrollWidth,
        fitView: true,
        fitCenter: true,
        // linkCenter: true, // 指向节点的中心，（注意:看不到中心）
        layout: {
          // 启用力布局
          type: 'force',
          // 节点强度, 数值越大节点之间的距离越远
          nodeStrength: 1000,
          // 防止重叠
          preventOverlap: true,
          // 节点大小
          nodeSize: 180,
          // 边缘强度
          edgeStrength: 0.1,
          // 链接距离
          linkDistance: 1000,
          center: [0, 0],
          gravity: 20,
          speed: 2,
          // 是否聚集
          clustering: true,
          // 集群重力
          clusterGravity: 30,
          maxIteration: 2000,
          workerEnabled: true
        },
        modes: {
          // 支持的 behavior
          default: [
            {
              type: 'drag-canvas'
            }, // 画布拖拽
            'zoom-canvas', // 画布缩放
            'hover-node', // 节点悬停
            'select-node', // 节点选择
            'hover-edge', // 边悬停
            // 'keyboard', // 键盘交互
            'customer-events', // 自定义事件
            'add-menu', // 添加菜单
            'drag-node',
            'click-select'
            // {
            //   type: 'tooltip',
            //   formatText: function formatText(model) {
            //     return model.name
            //   },
            //   stroke: '#b8c3ce'
            // }
            // {
            //   stroke: '#b8c3ce',
            //   type: 'edge-tooltip',
            //   formatText: function formatText(model, e) {
            //     var edge = e.item
            //     return (
            //       '来源：' +
            //       edge.getSource().getModel().name +
            //       '<br/>去向：' +
            //       edge.getTarget().getModel().name
            //     )
            //   }
            // }
          ],
          mulitSelect: ['mulit-select'], // 多选
          addEdge: ['add-edge'] // 添加边
          // moveNode: ['drag-item'] // 拖拽节点 开启后会导致拖拽和内部自带的冲突
        },
        edge: {
          shape: 'arc',
          fill: 'yellow',
          style: {
            endArrow: true,
            fill: 'yellow',
            stroke: 'yellow',
            color: 'yellow'
          }
        },
        // nodeStateStyles: {
        //   hover: {
        //     fill: '#b8c3ce'
        //   },
        //   running: {
        //     stroke: 'steelblue'
        //   }
        // },
        defaultEdge: {
          // shape: 'arc', // 边的形状
          // type: 'customArcWithArrow',
          // shape: 'flow-line',
          type: 'line',
          fill: '#b8c3ce', // 这个属性加上，文字就有阴影
          color: '#b8c3ce',
          labelCfg: {
            style: {
              lineAppendWidth: 10,
              // 控制连线文字的颜色
              // fill: '#b8c3ce',
              color: '#fff',
              stroke: '#fff',
              endArrow: true,
              arrow: {
                size: 40
              },
              radius: 40,
              offset: 1200
            },
            autoRotate: true
          }
        },
        edgeStateStyles: {
          selected: {
            // fill: '#fff'
            stroke: '#6ab7ff'
          },
          style: {
            stroke: '#fff'
            // fill: '#b8c3ce'
          }
        },
        transforms: ['process-parallel-edges'],
        behaviors: ['drag-element']
      })

      _that.graph.on('node:dragstart', ({ item, e }) => {
        // 实现抖动
        _that.draggingNodeId = item.getModel().id
        // _that.graph.layout() // 不用重新布局了，取消力布局，添加抖动
      })
      _that.graph.on('node:drag', ({ item, e }) => {
        if (_that.draggingNodeId) {
          const nodes = _that.graph.getNodes()
          nodes.forEach(node => {
            const model = node.getModel()
            if (model.id !== _that.draggingNodeId) {
              // Apply shake effect
              const shakeAmount = Math.floor(Math.random() * 10) + 1 // 震动量
              const shakeFrequency = Math.random() * (0.05 - 0.01) + 0.01 // 震动频率
              // 计算抖动偏移量
              const shakeOffsetX =
                Math.sin(Date.now() * shakeFrequency) * shakeAmount
              const shakeOffsetY =
                Math.cos(Date.now() * shakeFrequency) * shakeAmount

              // 更新节点位置,y轴可选
              _that.graph.updateItem(node, {
                x: model.x + shakeOffsetX
                // y: model.y + shakeOffsetY
              })
            }
          })

          // 用动画更新节点的位置
          // _that.graph.layout()
          _that.graph.paint()
        }
        this.refreshDragedNodePosition(e)
      })
      _that.graph.on('node:dragend', function(e) {
        // _that.draggingNodeId = null
        // 通过重新布局图形来重置抖动效果
        // _that.graph.layout()
        _that.graph.paint()
        e.item.get('model').fx = null
        e.item.get('model').fy = null
      })
      function refreshDragedNodePosition(e) {
        var model = e.item.get('model')
        model.fx = e.x
        model.fy = e.y
      }

      // 节点点击
      _that.graph.on('node:click', function(evt) {
        const { item } = evt
        const model = item.getModel()
        // 打开详情弹窗
        _that.$bus.$emit('drawer', model)
      })
      // 节点滑入
      _that.graph.on('node:mouseenter', function(evt) {
        var node = evt.item
        var model = node.getModel()
        _that.graph.setItemState(node, 'hover', true)
        _that.graph.updateItem(node, {
          label: model.name,
          labelCfg: {
            style: {
              fill: 'red'
            }
          }
        })
      })
      // 节点离开
      _that.graph.on('node:mouseleave', function(evt) {
        var node = evt.item
        var model = node.getModel()
        _that.graph.updateItem(node, {
          label: model.name.slice(0, 7),
          labelCfg: {
            style: {
              fill: '#565758'
            }
          }
        })
        _that.graph.setItemState(node, 'hover', false)
      })
      // 画布拖拽离开
      _that.graph.on('canvas:dragend', e => {
        // 处理拖拽结束事件
        _that.graph.off('canvas:dragend')
        _that.graph.off('node:dragend')
        _that.graph.off('canvas:dragstart')
        _that.graph.off('canvas:drag')
        _that.graph.off('canvas:dragend')
      })
      /** 画布网格，是否需要 */
      // _that.grid = new Grid()
      // _that.graph.addPlugin(_that.grid)
      const { editor, command } = _that.$parent
      editor.emit('afterAddPage', { graph: _that.graph, command })

      var edges = _that.graph.getEdges()
      edges.forEach(function(edge) {
        edge.getGraphicGroup().set('capture', false) // 移除边的捕获，提升图形拾取效率
      })
      // 加载数据
      _that.readData()
    },
    readData() {
      let data = this.data
      window.graph = this.graph
      if (Object.keys(data).length > 0) {
        this.graph.read(data)
        let timer = setTimeout(() => {
          this.$bus.$emit('autoCanvas')
          clearTimeout(timer)
          this.$bus.$emit('closeLoading', false)
          this.graph.updateLayout({
            type: 'd3force',
            preventOverlap: true,
            alpha: 0,
            alphaMin: 0.5,
            alphaTarget: 0
          })
        }, 1000)
      } else {
        // 如果查询出的结果没有数据，也要把loading遮罩层去掉
        this.$bus.$emit('closeLoading', false)
      }
    }
  },
  beforeDestroy() {
    this.$bus.$off('updateJsonData')
    this.graph.destroy()
  }
}
</script>

<style>
.graph-container > div {
  z-index: 1 !important;
}

.graph-container > canvas {
  position: relative;
  z-index: 10;
}

.graph-container {
  position: relative;
  width: 100%;
  height: 72vh;
}

.g6-tooltip {
  border: 1px solid #e2e2e2;
  border-radius: 4px;
  font-size: 12px;
  color: #545454;
  background-color: rgba(255, 255, 255, 0.9);
  padding: 10px 8px;
  box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
